#pragma once
#include <cstring>
#include <cstdlib>
#include <cassert>

namespace KRPC {

template<std::size_t N>
static inline std::size_t pad(std::size_t sz)
{
	auto left = (sz & N);
	return (left > 0) ? (sz + N - left) : sz;
}

class Buffer
{
public:
	Buffer() : m_buf(nullptr), m_len(0), m_size(0) {}
	Buffer(std::size_t initsz, std::size_t wz = 0) : m_buf(nullptr), m_len(0), m_size(0)
	{
        assert(initsz >= wz);
		resize(initsz);
		reset(wz);
	}
    ~Buffer() {free();}

	Buffer(const Buffer &buffer) = delete;
	Buffer(Buffer &&buffer) 
	{
		m_buf = buffer.m_buf;
		m_len = buffer.m_len;
		m_size = buffer.m_size;
		buffer.m_buf = nullptr;
		buffer.m_len = buffer.m_size = 0;
	}
	
	Buffer & operator=(const Buffer &buffer) = delete;
	Buffer & operator=(Buffer &&buffer)
	{
		free();
		m_buf = buffer.m_buf;
		m_len = buffer.m_len;
		m_size = buffer.m_size;
		buffer.m_buf = nullptr;
		buffer.m_len = buffer.m_size = 0;
		return *this;
	}

	void write(const char *data, size_t datalen)
	{
		if (datalen == 0 || m_size < m_len)
			return;
		auto left = m_size - m_len;
		if (left < datalen)
			resize(pad<1024>(m_len + datalen));
		memcpy((char *)m_buf + m_len, data, datalen);
        m_len += datalen;
	}

	void *data() {return m_buf;}
	const void *data() const noexcept {return m_buf;}
    std::size_t len() const noexcept {return m_len;}
	std::size_t size() const noexcept {return m_size;}

    explicit operator bool() const { return (m_buf != nullptr && m_len > 0); }

	void reset(std::size_t wz = 0) 
	{
		if (wz > m_size) {
			m_len = m_size;
		} else {
			m_len = wz;
		}
	}

	void resize(std::size_t sz) 
	{
		if (sz <= m_size)
			return;
		void *buf = (void *)realloc(m_buf, sz);
		if (buf != nullptr) {
			m_buf = buf;
			m_size = sz;
		}
	}

	void free() 
	{
		if (m_buf != nullptr) {
			::free(m_buf);
			m_buf = nullptr;
			m_len = m_size = 0;
		}
	}

private:
	void 		*m_buf;		//数据内容指针
	std::size_t  m_len;		//数据实际长度
	std::size_t  m_size;	//数据所使用的内存大小
};

} //endof namespace KRPC